<?php
namespace app\common\service;
use app\common\library\CommonFun;
use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise;

/**
 * 异步获取数据服务
 * @App	
 * @Group 
 * @Action AsyncDataService
 * @author lilei
 * @date 2019年1月5日
 *
 */
class AsyncDataService {
	
	/**
	 * HttpClient
	 * @var \GuzzleHttp\Client
	 */
	var $client;
	
	/**
	 * 基础Uri网关
	 * @var string
	 */
	var $base_uri;
	
	/**
	 * Request Option 配置
	 * @var array
	 */
	var $options = [];
	
	/**
	 * 请求头信息
	 */
	var $request_headers = [];
	
	/**
	 * 表示等待服务器响应超时的最大值，使用 0 将无限等待 (默认行为).
	 * @var int|float
	 */
	private $connect_timeout = 10;
	
	/**
	 * 请求超时的秒数。使用 0 无限期的等待(默认行为)。
	 * @var int|float
	 */
	private $timeout = 10;
	
	/**
	 * @var bool 是否允许重定向
	 */
	private $allow_redirects = true;
	
	/**
	 * Option属性列表
	 * @var array
	 */
	const optionList = ['base_uri','timeout','connect_timeout','allow_redirects'];
	
	// 请求返回类型标示
	const returnTypeString = "string";
	const returnTypeNumber = "number";
	const returnTypeArray = "array";
	
	/**
	 * 数据方法列表
	 * @var array
	 */
	var $functions = [];
	
	/**
	 * 请求返回数据
	 * @var array
	 */
	var $results;
	
	/**
	 * 构造方法
	 * @param string $http_server_config Http服务器配置名称
	 * @return boolean
	 */
	function __construct( $http_server_config="default" ) {
		// 加载配置
		CommonFun::get_other_config ( "HttpServerConfig", 2 );
		$base_uri = C("http_server_config.{$http_server_config}");
		if ( !$base_uri ) {
			CommonFun::make_exception("没有获取到内置服务器配置");
			return false;
		}
		// 基础Uri网关
		$this->base_uri = rtrim($base_uri, "/")."/";
		
		// 设置Option
		if ( self::optionList ) {
			foreach ( self::optionList as $v ) {
				if ( isset( $this->{$v} ) ) {
					$this->setOptions( $v, $this->{$v} );
				}
			}
		}
		// 请求客户端
		$this->client = new Client( $this->options );
	}
	
	/**
	 * 设置请求类和方法
	 * @param string $class 类名称
	 * @param string $func	类方法
	 * @param array $param	参数列表 同call_user_func_array($callback, $param_arr) 的 $param_arr参数
	 * @param string $return_type 返回类型
	 * @return AsyncDataService
	 */
	public function setRequestClassFunction( $class, $func, array $param = [], $return_type='' ) {
		// 构建请求列表
		$key = "{$class}/{$func}/".CommonFun::json_encode2($param);
		$this->functions[$key] = [
				'class' => $class,
				'function' => $func,
				'param' => $param,
				'return_type' => $return_type,
		];
		
		return $this;
	}
	
	/**
	 * 生成并发请求参数列表
	 */
	private function genPromises() {
		if ( !$this->functions ) {
			return false;
		}
		$promises = [];
		
		foreach ( $this->functions as $k=>$v ) {
			$class = $v['class'];
			$func = $v['function'];
			$param = $v['param'];
			$return_type = $v['return_type'];
			$uri = "/{$class}/{$func}";
			if ( $param ) {
				$promises[$k] = $this->client->postAsync($uri, ['form_params'=>$param]);
			}else {
				$promises[$k] = $this->client->getAsync($uri);
			}
		}
		return $promises;
	}
	
	/**
	 * 执行请求
	 */
	public function run() {
		$promises = $this->genPromises();
		if ( !$promises ) {
			return false;
		}
		try {
			$results = Promise\unwrap($promises);
		} catch (\Exception $e) {
			CommonFun::make_exception($e->getMessage());
			return false;
		}
		
		if ( !$results ) {
			return false;
		}
		foreach ( $results as $k=>&$v ) {
			$v = (string)$v->getBody();
			$return_type = $this->functions[$k]['return_type'];
			if ( $return_type == self::returnTypeArray ) {
				$v = json_decode($v, true);
			}
		}
		$this->results = $results;
		//return $results;
		return $this;
	}
	
	/**
	 * 获取返回数据
	 * @param string $class 类名称
	 * @param string $func	类方法
	 * @param array $param	参数类表 同call_user_func_array($callback, $param_arr) 的 $param_arr参数
	 */
	public function getResponseData( $class, $func, array $param = [] ) {
		$key = "{$class}/{$func}/".CommonFun::json_encode2($param);
		return $this->results[$key];
	}
	
	/**
	 * @param $name
	 * @param $value
	 * @return self
	 */
	public function __set($name, $value)
	{
		// TODO: Implement __set() method.
		if ( in_array( $name, self::optionList ) ) {
			$this->setOptions($name, $value);
		}
		return $this;
	}
	
	public function __get($name)
	{
		// TODO: Implement __get() method.
		return $this->{$name};
	}
	
	/**
	 * 设置Request Option 配置
	 * @param mixed $name 配置名称
	 * @param mixed $value 配置值
	 * @return $this
	 */
	public function setOptions( $name, $value ) {
		if ( is_array($name) ) {
			$this->options = array_merge($this->options, $name);
		}else {
			$this->options[$name] = $value;
		}
		return $this;
	}
	
	/**
	 * 设置头信息
	 * @param string|array $name 名称
	 * @param string $value 值
	 * @return $this
	 */
	public function setHeaders( $name, $value='' ) {
		if ( is_array($name) ) {
			$this->request_headers = array_merge($this->request_headers, $name);
		}else {
			$this->request_headers[$name] = $value;
		}
		if ( $this->request_headers ) $this->setOptions( 'headers', $this->request_headers );
		return $this;
	}
	
	
	
	
	
	
}